package com.quanyan.pay.component.alipay;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.reflect.TypeToken;
import com.quanyan.alipay.config.AlipayConfig;
import com.quanyan.alipay.protocal.*;
import com.quanyan.alipay.util.AlipaySubmit;
import com.quanyan.api.APIResponse;
import com.quanyan.common.encrypt.Coder;
import com.quanyan.common.utils.DateUtils;
import com.quanyan.common.utils.GsonUtils;
import com.quanyan.common.utils.ObjectUtil;
import com.quanyan.common.utils.XmlUtils;
import com.quanyan.pay.component.RespRefundMsg;
import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.io.xml.DomDriver;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.Node;
import org.dom4j.io.SAXReader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import java.lang.reflect.Type;
import java.math.BigDecimal;
import java.util.*;

/**
 * 阿里支付组件
 *
 * @author songzj
 * @date 16/5/27-15:17
 */
@Component("alipayComponent")
public class AlipayComponent {


    private Logger logger = LoggerFactory.getLogger(AlipayComponent.class);

    /**
     * 阿里支付App支付
     *
     * @param subject
     * @param describe
     * @param orderNo
     * @param payAmount
     * @return
     */
    public String alipayAppProcess(String subject, String describe, String orderNo, BigDecimal payAmount, Integer payTimeOut,  AlipayConfig alipayConfig) {
        return new AliPayReqData(orderNo, subject, describe, payAmount, payTimeOut, alipayConfig).sign();
    }


    public RespRefundMsg alipayRefundNoPwdRequest(String batchNo, String tsn, BigDecimal refundAmount, String refundReason, AlipayConfig alipayConfig) {
        try {
            AlipayRefundNoPwdData alipayRefundNoPwdData = new AlipayRefundNoPwdData(batchNo, tsn, refundAmount, refundReason, alipayConfig);
            logger.warn("request alipay refund : {}", alipayRefundNoPwdData);
            String result = AlipaySubmit.buildRequest("", "", alipayRefundNoPwdData.getStringMap(), alipayConfig,AlipaySubmit.ALIPAY_GATEWAY_NEW,Coder.KEY_MD5);
            logger.warn("request alipay refund : {}", result);

            XStream xStream = new XStream(new DomDriver());
            xStream.alias("alipay", AlipayRefundNoPwdData.AliPayRefundResult.class);
            AlipayRefundNoPwdData.AliPayRefundResult aliPayRefundResult = (AlipayRefundNoPwdData.AliPayRefundResult) xStream.fromXML(result);
            if (aliPayRefundResult.getIs_success().equals("T")
                    || aliPayRefundResult.getIs_success().equals("P")) {
                return new RespRefundMsg(true, "提交退款申请成功!");
            } else {
                return new RespRefundMsg(false, aliPayRefundResult.getError());
            }
        } catch (Exception e) {
            logger.error(ObjectUtil.getFullStackTraceToString(e));
            return new RespRefundMsg(false, e.getMessage());
        }

    }

    public AliRespQueryTrade queryTrade(String orderNo, AlipayConfig alipayConfig) {
        Map<String, String> reqParams = new HashMap<String, String>();
        try {
            reqParams.put("service", "single_trade_query");
            reqParams.put("partner", alipayConfig.getPartner());
            reqParams.put("_input_charset", alipayConfig.getInput_charset());
            reqParams.put("out_trade_no", orderNo);
            String result = AlipaySubmit.buildRequest("", "", reqParams, alipayConfig,AlipaySubmit.ALIPAY_GATEWAY_NEW,Coder.KEY_MD5);

            //logger.info("支付宝查询交易信息：请求{}。晌应{}。", reqParams, result);

            AliRespQueryTrade aliRespQueryTrade = XmlUtils.xmlStrToEntity(result, AliRespQueryTrade.class);
            return aliRespQueryTrade;
        } catch (Exception e) {
            //logger.error("调用支付宝交易查询接口出错。reqParams=" + reqParams, e);
        }
        return null;
    }

    public APIResponse<AliPayTradePayResp> scanPay(AliPayTradePayReq aliPayTradePayReq, AlipayConfig alipayConfig) {
        Map<String, String> reqParams = new HashMap<String, String>();
        try {
            reqParams.put("app_id", alipayConfig.getApp_id());
            reqParams.put("method", "alipay.trade.pay");
            reqParams.put("charset", alipayConfig.getInput_charset());
            reqParams.put("timestamp", DateUtils.convertFormatDateToString(DateUtils.DAY_DATE_FORMAT_HH_MM_SS,new Date()));
            reqParams.put("version", "1.0");
            reqParams.put("sign_type",Coder.KEY_RSA);
            reqParams.put("biz_content", GsonUtils.toJson(aliPayTradePayReq));
            String result = AlipaySubmit.buildRequest("", "", reqParams, alipayConfig,AlipaySubmit.ALIPAY_OPEN_API, Coder.KEY_RSA);
            logger.error("调用支付宝扫描枪支付接口返回结果："+result);
            //logger.info("支付宝查询交易信息：请求{}。晌应{}。", reqParams, result);
            Gson gson = new GsonBuilder().setDateFormat("yyyy-MM-dd HH:mm:ss").create();
            Type aliPayTradePayRespType = new TypeToken<AliPayTradePayResp>(){}.getType();
            AliPayTradePayResp aliPayTradePayResp = gson.fromJson(result,aliPayTradePayRespType);
            if(null==aliPayTradePayResp||null== aliPayTradePayResp.getAliPayTradePayRes()){
                //出异常当有密支付，主动轮询接口，防止支付宝超时
                logger.error("调用支付宝扫描枪支付接口出错。reqParams=" + reqParams);
                AliPayTradePayRes aliPayTradePay = new AliPayTradePayRes();
                aliPayTradePay.setCode("20000");
                aliPayTradePayResp.setAliPayTradePay(aliPayTradePay);
                return APIResponse.returnSuccess(aliPayTradePayResp);
            }else if("10000".equals(aliPayTradePayResp.getAliPayTradePayRes().getCode())
                    ||"10003".equals(aliPayTradePayResp.getAliPayTradePayRes().getCode())
                    ||"20000".equals(aliPayTradePayResp.getAliPayTradePayRes().getCode())){
                return APIResponse.returnSuccess(aliPayTradePayResp);
            }else {
                return APIResponse.returnFail(aliPayTradePayResp.getAliPayTradePayRes().getSub_msg());
            }
        } catch (Exception e) {
            //出异常当有密支付，主动轮询接口，防止支付宝超时
            logger.error("调用支付宝扫描枪支付接口出错。reqParams=" + reqParams, e);
            AliPayTradePayResp aliPayTradePayResp = new AliPayTradePayResp();
            AliPayTradePayRes aliPayTradePay = new AliPayTradePayRes();
            aliPayTradePay.setCode("20000");
            aliPayTradePayResp.setAliPayTradePay(aliPayTradePay);
            return APIResponse.returnSuccess(aliPayTradePayResp);
        }
       // return null;
    }

    public APIResponse<AliPayTradePrecreateResp> scanCodePay(AliPayTradePrecreateReq aliPayTradePrecreateReq, AlipayConfig alipayConfig) {
        Map<String, String> reqParams = new HashMap<String, String>();
        try {
            reqParams.put("app_id", alipayConfig.getApp_id());
            reqParams.put("method", "alipay.trade.precreate");
            reqParams.put("charset", alipayConfig.getInput_charset());
            reqParams.put("timestamp", DateUtils.convertFormatDateToString(DateUtils.DAY_DATE_FORMAT_HH_MM_SS, new Date()));
            reqParams.put("version", "1.0");
            reqParams.put("sign_type", Coder.KEY_RSA);
            reqParams.put("notify_url",alipayConfig.getNotify_url());
            reqParams.put("biz_content", GsonUtils.toJson(aliPayTradePrecreateReq));
            String result = AlipaySubmit.buildRequest("", "", reqParams, alipayConfig, AlipaySubmit.ALIPAY_OPEN_API, Coder.KEY_RSA);
            logger.error("调用支付宝扫码支付接口返回结果：" + result);
            //logger.info("支付宝查询交易信息：请求{}。晌应{}。", reqParams, result);
            Gson gson = new GsonBuilder().setDateFormat("yyyy-MM-dd HH:mm:ss").create();
            Type AliPayTradePrecreateResp = new TypeToken<AliPayTradePrecreateResp>() {}.getType();
            AliPayTradePrecreateResp aliPayTradePrecreateResp = gson.fromJson(result, AliPayTradePrecreateResp);
            if(null == aliPayTradePrecreateResp || null == aliPayTradePrecreateResp.getAlipay_trade_precreate_response()){
                logger.error("调用支付宝扫码支付接口出错。reqParams=" + reqParams);
                return APIResponse.returnFail("调用支付宝扫码支付接口出错");
            }else if ("10000".equals(aliPayTradePrecreateResp.getAlipay_trade_precreate_response().getCode())) {
                return APIResponse.returnSuccess(aliPayTradePrecreateResp);
            } else {
                return APIResponse.returnFail(aliPayTradePrecreateResp.getAlipay_trade_precreate_response().getSub_msg());
            }
        } catch (Exception e) {
            //出异常当有密支付，主动轮询接口，防止支付宝超时
            logger.error("调用支付宝扫码支付接口未知异常。reqParams=" + reqParams, e);
            return APIResponse.returnFail("调用支付宝扫码支付接口未知异常");
        }

    }

    public RespRefundMsg scanRefund(AliPayTradeRefundReq aliPayTradeRefundReq, AlipayConfig alipayConfig) {
        Map<String, String> reqParams = new HashMap<String, String>();
        try {
            reqParams.put("app_id", alipayConfig.getApp_id());
            reqParams.put("method", "alipay.trade.refund");
            reqParams.put("charset", alipayConfig.getInput_charset());
            reqParams.put("sign_type",Coder.KEY_RSA);
            reqParams.put("timestamp", DateUtils.convertFormatDateToString(DateUtils.DAY_DATE_FORMAT_HH_MM_SS,new Date()));
            reqParams.put("version", "1.0");
            reqParams.put("biz_content", GsonUtils.toJson(aliPayTradeRefundReq));
            String result = AlipaySubmit.buildRequest("", "", reqParams, alipayConfig,AlipaySubmit.ALIPAY_OPEN_API,Coder.KEY_RSA);
            logger.error("调用支付宝扫描枪退款接口返回结果："+result);
            //logger.info("支付宝查询交易信息：请求{}。晌应{}。", reqParams, result);
            Gson gson = new GsonBuilder().setDateFormat("yyyy-MM-dd HH:mm:ss").create();
            Type AliPayTradeRefundResp = new TypeToken<AliPayTradeRefundResp>(){}.getType();
            AliPayTradeRefundResp aliPayTradeRefundResp=gson.fromJson(result,AliPayTradeRefundResp);
            //logger.info("支付宝查询交易信息：请求{}。晌应{}。", reqParams, result);
            if(null==aliPayTradeRefundResp||null== aliPayTradeRefundResp.getAlipayTradeRefundRes()){
                logger.error("支付宝扫描枪退款接口转换json异常。");
                return new RespRefundMsg(false, "支付宝扫描枪退款接口转换json异常。");
            }else if("10000".equals(aliPayTradeRefundResp.getAlipayTradeRefundRes().getCode())){
                RespRefundMsg respRefundMsg = new RespRefundMsg(true, "退款成功!");
                respRefundMsg.setRefundTime(aliPayTradeRefundResp.getAlipayTradeRefundRes().getGmt_refund_pay().getTime());
                respRefundMsg.setTradeNo(aliPayTradeRefundResp.getAlipayTradeRefundRes().getTrade_no());
                return respRefundMsg;
            }else {
                return new RespRefundMsg(false, aliPayTradeRefundResp.getAlipayTradeRefundRes().getSub_msg());
            }

        } catch (Exception e) {
            logger.error(ObjectUtil.getFullStackTraceToString(e));
            return new RespRefundMsg(false, e.getMessage());
        }
    }

    public APIResponse<AliPayTradeQueryResp> tradeQuery(AliPayTradeQueryReq aliPayTradeQuery , AlipayConfig alipayConfig) {
        Map<String, String> reqParams = new HashMap<String, String>();
        try {
            reqParams.put("app_id", alipayConfig.getApp_id());
            reqParams.put("method", "alipay.trade.query");
            reqParams.put("charset", alipayConfig.getInput_charset());
            reqParams.put("timestamp", DateUtils.convertFormatDateToString(DateUtils.DAY_DATE_FORMAT_HH_MM_SS,new Date()));
            reqParams.put("version", "1.0");
            reqParams.put("sign_type",Coder.KEY_RSA);
            reqParams.put("biz_content", GsonUtils.toJson(aliPayTradeQuery));
            String result = AlipaySubmit.buildRequest("", "", reqParams, alipayConfig,AlipaySubmit.ALIPAY_OPEN_API, Coder.KEY_RSA);
            logger.error("调用支付宝统一交易查询接口返回结果："+result);
            //logger.info("支付宝查询交易信息：请求{}。晌应{}。", reqParams, result);
            Gson gson = new GsonBuilder().setDateFormat("yyyy-MM-dd HH:mm:ss").create();
            Type aliPayTradePayRespType = new TypeToken<AliPayTradeQueryResp>(){}.getType();
            AliPayTradeQueryResp aliPayTradeQueryResp=gson.fromJson(result,aliPayTradePayRespType);
            if(null==aliPayTradeQueryResp||null== aliPayTradeQueryResp.getAlipayTradeQueryResponse()){
                logger.error("调用支付宝统一交易查询接口出错。");
                return APIResponse.returnFail("调用支付宝统一交易查询接口出错");
            }else if("10000".equals(aliPayTradeQueryResp.getAlipayTradeQueryResponse().getCode())
                    ||"10003".equals(aliPayTradeQueryResp.getAlipayTradeQueryResponse().getCode())
                    ||"20000".equals(aliPayTradeQueryResp.getAlipayTradeQueryResponse().getCode())){
                return APIResponse.returnSuccess(aliPayTradeQueryResp);
            }else {
                return APIResponse.returnFail(aliPayTradeQueryResp.getAlipayTradeQueryResponse().getSub_msg());
            }
        } catch (Exception e) {
            logger.error("调用支付宝统一交易查询接口出错。reqParams=" + reqParams, e);
            return APIResponse.returnFail(e.getMessage());
        }
    }

    public APIResponse btnStatusQuery(String batchNo,AlipayConfig alipayConfig){
        Map<String, String> reqParams = new HashMap<String, String>();
        try {
            reqParams.put("service", "btn_status_query");
            reqParams.put("partner", alipayConfig.getPartner());
            reqParams.put("_input_charset", alipayConfig.getInput_charset());
            reqParams.put("sign_type",Coder.KEY_RSA);
            reqParams.put("email", alipayConfig.getSeller());
            reqParams.put("batch_no",batchNo);
            String result = AlipaySubmit.buildRequest("", "", reqParams, alipayConfig,AlipaySubmit.ALIPAY_GATEWAY_NEW, Coder.KEY_MD5);
            logger.error("调用支付宝批次付款状态接口返回结果："+result);
            Map<String, String> returnMap = ObjectUtil.convertXmlToMap(result);

            if("T".equals(returnMap.get("is_success"))){
                //调用接口成功
                Document document = DocumentHelper.parseText(result);
                Element nodeElement = document.getRootElement();
                Element e = nodeElement.element("response").element("order").element("batch_status");
                if(null != e){
                    return APIResponse.returnSuccess(e.getText());
                }else{
                    return APIResponse.returnFail("没有该批次状态节点");
                }

            }else if("F".equals(returnMap.get("is_success"))){
                return APIResponse.returnFail(returnMap.get("error"));
            }else {
                return APIResponse.returnFail("调用支付宝批次付款状态接口错误");
            }
        } catch (Exception e) {
            logger.error("调用支付宝批次付款状态接口出错。reqParams=" + reqParams, e);
            return APIResponse.returnFail(e.getMessage());
        }
    }

    public APIResponse<AliPayTradeCloseResp> tradeClose(AliPayTradeCloseReq aliPayTradeCloseReq, AlipayConfig alipayConfig) {
        Map<String, String> reqParams = new HashMap<String, String>();
        try {
            reqParams.put("app_id", alipayConfig.getApp_id());
            reqParams.put("method", "alipay.trade.close");
            reqParams.put("charset", alipayConfig.getInput_charset());
            reqParams.put("timestamp", DateUtils.convertFormatDateToString(DateUtils.DAY_DATE_FORMAT_HH_MM_SS,new Date()));
            reqParams.put("version", "1.0");
            reqParams.put("sign_type",Coder.KEY_RSA);
            reqParams.put("biz_content", GsonUtils.toJson(aliPayTradeCloseReq));
            String result = AlipaySubmit.buildRequest("", "", reqParams, alipayConfig,AlipaySubmit.ALIPAY_OPEN_API, Coder.KEY_RSA);
            logger.error("调用支付宝统一交易关闭接口返回结果："+result);
            //logger.info("支付宝查询交易信息：请求{}。晌应{}。", reqParams, result);
            Gson gson = new GsonBuilder().setDateFormat("yyyy-MM-dd HH:mm:ss").create();
            Type aliPayTradeCloseRespType = new TypeToken<AliPayTradeCloseResp>(){}.getType();
            AliPayTradeCloseResp aliPayTradeCloseResp=gson.fromJson(result,aliPayTradeCloseRespType);
            if(null==aliPayTradeCloseResp||null== aliPayTradeCloseResp.getAlipayTradeCloseResponse()){
                logger.error("调用支付宝统一交易关闭接口出错。");
                return APIResponse.returnFail("调用支付宝统一交易关闭接口出错");
            }else if("10000".equals(aliPayTradeCloseResp.getAlipayTradeCloseResponse().getCode())&&"Success".equals(aliPayTradeCloseResp.getAlipayTradeCloseResponse().getMsg())){
                return APIResponse.returnSuccess(aliPayTradeCloseResp);
            }else {
                return APIResponse.returnFail(aliPayTradeCloseResp.getAlipayTradeCloseResponse().getSub_msg());
            }
        } catch (Exception e) {
            logger.error("调用支付宝统一交易关闭接口出错。reqParams=" + reqParams, e);
            return APIResponse.returnFail(e.getMessage());
        }
    }
}
